empty_element = ["input"]
global_element_count = 0
class Element:
    tag: str
    id: str
    h5attrs: dict
    jsattrs: dict
    h5attr_startwith: str
    jsattr_startwith: str
    is_empty_element: bool
    child: list
    js: list[str]
    def __init__(self) -> None:
        self.tag = "div"
        self.id = f"element_{global_element_count}"
        self.h5attrs = {}
        self.jsattrs = {}
        self.h5attr_startwith = "&"
        self.jsattr_startwith = "*"
        self.is_empty_element = False
        self.child = []
        self.js = []

class EmptyElement(Element):
    def __init__(self) -> None:
        super().__init__()
        self.is_empty_element = True

class imported_pool: pass
ImportedPool = imported_pool()

def loadImportable(json: dict):
    for key in json.keys():
        exec(f'ImportedPool.{key} = imported_pool()')
        for element in json[key]:
            exec(f'ImportedPool.{key}.{element} = {json[key][element]}')
            print(f"imported {key}.{element}")

def parseJson(json: dict):
    global global_element_count
    global_element_count += 1
    tag = Element()
    tag.id = f"element_{global_element_count}"
    for key in json.keys():
        item = json[key]

        if key.startswith("$"):
            key = key.replace("$", "")
            if key == "tag":
                if item in empty_element:
                    tag = EmptyElement()
                tag.tag = item
            elif key == "id":
                tag.id = item
            elif key == "tag_from":
                print("used", item)
                tag = parseJson(eval(f'ImportedPool.{item}'))
            elif key == "child" and not tag.is_empty_element:
                for i in item:
                    tag.child.append(parseJson(i))
            else:
                print("unknown attr", key)
        elif key.startswith("&"):
            key = key.replace("&", "")
            tag.h5attrs.update({key: item})
        elif key.startswith("*"):
            key = key.replace("*", "")
            tag.jsattrs.update({key: item})
        else:
            raise KeyError(key)
    return tag

def toJS(element: Element):
    global global_element_count
    global_element_count += 1
    if not isinstance(element, Element):
        return []
    if element.tag != "body":
        element.js.append(f'let {element.id} = document.createElement("{element.tag}");\n')
    else:
        element.id = "document.body"
    for key in element.h5attrs.keys():
        value = element.h5attrs[key]
        element.js.append(f'{element.id}.setAttribute("{key}", "{value}");\n')
    for key in element.jsattrs.keys():
        value = element.jsattrs[key]
        element.js.append(f'{element.id}.{key} = {value};\n')
    if element.is_empty_element or not len(element.child):
        return element.js
    for child_element in element.child:
        element.js += toJS(child_element)
        element.js.append(f'{element.id}.appendChild({child_element.id});\n')
    return element.js

def public(filename: str, js: list):
    with open(filename, 'w', encoding="utf-8") as f:
        f.write('<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><script>\nwindow.onload = () => {\n')
        f.writelines(js)
        f.write('};\n</script><title>Document</title></head><body></body></html>')